<?php


namespace app\common\lib\redis;


/**
 * 1. simple string. 简单的字符串.
 *      "+OK\r\n"
 * 2. error. 就是表示这是一个错误(异常)情况
 *      "-ERR unknown command 'foobar'\r\n"
 * 3. integer 表示这是一个整数
 *      ":1000\r\n"
 * 4. bulk string. 表示是长字符串,但是必须小于512M.
 *      "$0\r\n"   --$后面的0表示这是一个空字符串
 *      "$-1\r\n"  -- $后面的-1表示这是一个null字符串,Null Bulk String要求客户端返回空对象,而不能简单地返回个空字符串
 *      "$6\r\nABCDEF\r\n"  -- ABCDEF是6个字节,所以$后面是6
 * 5. arrays. 表示这是一个数组,数组元素可以是上面的任意一种类型,也可以是一个数组
 *      "*0\r\n"   --*后面的0表示表示空的数组

        "*-1\r\n"  --*后面的-1表示表示是null数组

        "*5\r\n     -- *5表示这是一个拥有5个元素的数组
        +bar\r\n    -- 第1个元素是简单的字符串
        -unknown command\r\n      -- 第2个元素是个异常
        :3\r\n      -- 第3个元素是个整数
        $3\r\n      -- 第4个元素是长度为3个字节的长字符串foo
        foo\r\n     -- 第4个元素的内容
         *3\r\n      -- 第5个元素又是个数组
        :1\r\n      -- 第5个元素数组的第1元素
        :2\r\n      -- 第5个元素数组的第2元素
        :3\r\n      -- 第5个元素数组的第3元素
        "
 * @Author: Li Guo Xin <guoxinlee129@gmail.com>
 * @Date: 2020/5/11
 * @Time: 17:37
 */
class RedisLib
{
    function recv(): ?Response
    {
        /*
            用单行回复，回复的第一个字节将是“+”
            错误消息，回复的第一个字节将是“-”
            整型数字，回复的第一个字节将是“:”
            批量回复，回复的第一个字节将是“$”
            多个批量回复，回复的第一个字节将是“*”
         */
        $result = new Response();
        $str = $this->client->recv($this->timeout);
        if (empty($str)) {
            $result->setStatus($result::STATUS_TIMEOUT);
            return $result;
        }
        /**
         * 去除每行的\r\n
         */
        $str = substr($str, 0, -2);
        $op = substr($str, 0, 1);
        $result = $this->opHandel($op, $str);
        return $result;
    }

    /**
     * 字符串处理方法
     * opHandel
     * @param $op
     * @param $value
     * @return Response
     * @author Tioncico
     * Time: 11:52
     */
    protected function opHandel($op, $value)
    {
        $result = new Response();
        switch ($op) {
            case '+':
            {
                $result = $this->successHandel($value);
                break;
            }
            case '-':
            {
                $result = $this->errorHandel($value);
                break;
            }
            case ':':
            {
                $result = $this->intHandel($value);
                break;
            }
            case '$':
            {
                $result = $this->batchHandel($value);
                break;
            }
            case "*":
            {
                $result = $this->multipleBatchHandel($value);
                break;
            }
        }
        return $result;
    }

    /**
     * 状态类型处理
     * successHandel
     * @param $value
     * @return Response
     * @author Tioncico
     * Time: 11:52
     */
    protected function successHandel($value): Response
    {
        $result = new Response();
        $result->setStatus($result::STATUS_OK);
        $result->setData(substr($value, 1));
        return $result;
    }

    /**
     * 错误类型处理
     * errorHandel
     * @param $value
     * @return Response
     * @author Tioncico
     * Time: 11:53
     */
    protected function errorHandel($value): Response
    {
        $result = new Response();
        //查看空格位置
        $spaceIndex = strpos($value, ' ');
        //查看换行位置
        $lineIndex = strpos($value, PHP_EOL);
        if ($lineIndex === false || $lineIndex > $spaceIndex) {
            $result->setErrorType(substr($value, 1, $spaceIndex - 1));

        } else {
            $result->setErrorType(substr($value, 1, $lineIndex - 1));
        }
        $result->setStatus($result::STATUS_ERR);
        $result->setMsg(substr($value, 1));
        return $result;
    }

    /**
     * int类型处理
     * intHandel
     * @param $value
     * @return Response
     * @author Tioncico
     * Time: 11:53
     */
    protected function intHandel($value): Response
    {
        $result = new Response();
        $result->setStatus($result::STATUS_OK);
        $result->setData((int)substr($value, 1));
        return $result;
    }

    /**
     * 批量回复处理
     * batchHandel
     * @param $str
     * @param $timeout
     * @return bool|string
     * @author Tioncico
     * Time: 17:13
     */
    protected function batchHandel($str)
    {
        $response = new Response();
        $strLen = substr($str, 1);
        //批量回复,继续读取字节
        $len = 0;
        $buff = '';
        if ($strLen == 0) {
            $this->client->recv($this->timeout);
            $response->setData('');
        } else {
            while ($len < $strLen) {
                $strTmp = $this->client->recv($this->timeout);
                $len += strlen($strTmp);
                $buff .= $strTmp;
            }
            $response->setData(substr($buff, 0, -2));
        }
        $response->setStatus($response::STATUS_OK);
        return $response;
    }

    /**
     * 多条批量回复
     * multipleBatchHandel
     * @param $value
     * @return Response
     * @author Tioncico
     * Time: 14:33
     */
    protected function multipleBatchHandel($value)
    {
        $result = new Response();
        $len = substr($value, 1);
        if ($len == 0) {
            $result->setStatus($result::STATUS_OK);
            $result->setData([]);
        } elseif ($len == -1) {
            $result->setStatus($result::STATUS_OK);
            $result->setData(null);
        } else {
            $arr = [];
            while ($len--) {
                $str = $this->client->recv($this->timeout);
                $str = substr($str, 0, -2);
                $op = substr($str, 0, 1);
                $response = $this->opHandel($op, $str);
                $arr[] = $response->getData();
            }
            $result->setStatus($result::STATUS_OK);
            $result->setData($arr);
        }
        return $result;
    }

}

$recv = $client->recv();
